<script lang="ts" setup>
import dayjs from 'dayjs'
import type { TablePaginationConfig } from 'ant-design-vue'
import { Modal, message } from 'ant-design-vue'
import { ExclamationCircleOutlined, PlayCircleTwoTone, QuestionCircleOutlined } from '@ant-design/icons-vue'
import type { SorterResult } from 'ant-design-vue/es/table/interface'
import { computed, h, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import TaskStatus from './components/TaskStatus.vue'
import { orderMap } from './config'
import PageWrapper from '@/components/PageWrapper.vue'
import type { DistributionParams } from '@/api/paths/types'
import { api } from '@/api'
import type { Direction, Task } from '@/api'
import { hasIntersection } from '@/utils'

const { t } = useI18n()
const searchKey = ref<string>()

const taskTableColumns = computed(() => [
  {
    dataIndex: 'task_name',
    title: t('vul.task.taskName'),
    fixed: 'left',
  },
  {
    dataIndex: 'description',
    title: t('vul.task.taskDesc'),
    width: 200,
  },
  {
    key: 'host_num',
    dataIndex: 'host_num',
    title: t('vul.task.hostCount'),
    sorter: true,
    width: 90,
    align: 'center',
  },
  {
    dataIndex: 'task_type',
    title: t('vul.task.taskType'),
    width: 140,
    filters: [
      {
        text: 'cve fix',
        value: 'cve fix',
      },
      {
        text: 'repo set',
        value: 'repo set',
      },
      {
        text: 'cve rollback',
        value: 'cve rollback',
      },
      {
        text: 'hotpatch remove',
        value: 'hotpatch remove',
      },
    ],
  },
  {
    dataIndex: 'cluster_name',
    title: t('vul.cluster'),
    align: 'center',
  },
  {
    dataIndex: 'status',
    title: t('vul.task.status'),
    align: 'center',
    width: 140,
  },
  {
    key: 'create_time',
    dataIndex: 'create_time',
    title: t('vul.task.generateTime'),
    sorter: true,
  },
  {
    dataIndex: 'operation',
    title: t('common.operation'),
    align: 'center',
    fixed: 'right',
  },
])

const filterMap: Record<string, string[]> = reactive({
  task_type: [],
})

const cutOff = computed(() => (originStr: string) => {
  return originStr.length < 10 ? originStr : `${originStr.substring(0, 10)}...`
})

const taskTableData = ref<Task[]>([])

const tableState = reactive<{
  selectedRowKeys: string[]
  loading: boolean
}>({
  selectedRowKeys: [],
  loading: false,
})

const pagination = reactive({
  total: 0,
  current: 1,
  pageSize: 10,
  showTotal: (total: number) => t('common.total', { count: total }),
  showSizeChanger: true,
  pageSizeOptions: ['10', '20', '30', '40'],
})

let timer: NodeJS.Timeout | null
const runningTask = ref<string[]>([])

async function queryTasks(searchKey?: string, sortKey?: string, sortDir?: Direction) {
  if (timer) {
    runningTask.value = []
    clearTimeout(timer)
    timer = null
  }
  /**
   * query task status,if is running re try in 3s
   */
  const queryTasksStatus = async (taskIds: string[]) => {
    const [, res] = await api.getTasksStatus(taskIds)
    if (res && taskTableData.value.length) {
      taskTableData.value.forEach(task => {
        const status = res.result[task.task_id]
        if (status) {
          task.status = status
          if (task.status.running) runningTask.value.push(task.task_id)
        }
      })
      if (runningTask.value.length > 0) {
        timer = setTimeout(() => {
          queryTasksStatus(runningTask.value)
        }, 5000)
      } else {
        if (timer) {
          clearTimeout(timer)
          timer = null
        }
      }
    }
  }

  tableState.loading = true
  const [, res] = await api.getTasks({
    page: pagination.current,
    per_page: pagination.pageSize,
    sort: sortKey,
    direction: sortDir,
    filter: {
      task_name: searchKey || undefined,
      task_type: filterMap.task_type,
    },
  })
  if (res) {
    taskTableData.value = res.result
    pagination.total = res.total_count
    const taskIds = taskTableData.value.map(task => task.task_id)
    if (taskIds.length > 0) await queryTasksStatus(taskIds)
  }
  tableState.loading = false
}

function handleTableChange(
  page: TablePaginationConfig,
  filters: Record<string, string[] | null>,
  sorter: SorterResult<Task>,
) {
  page.current && (pagination.current = page.current)
  page.pageSize && (pagination.pageSize = page.pageSize)
  filterMap.task_type = filters.task_type ?? []
  const sortKey = sorter.columnKey || undefined
  const sortDir = sorter.order || undefined

  queryTasks(searchKey.value, sortKey as string, orderMap[sortDir as Direction])
}

function onSelectChange(selectedRowKeys: string[]) {
  tableState.selectedRowKeys = selectedRowKeys
}

/**
 * delete tasks with task id
 * distrubition
 */
async function deleteTask(taskId: string[] | string) {
  let taskIds = taskId
  const params: DistributionParams<{ task_list: string[] }> = {}
  if (typeof taskId === 'string') taskIds = [taskId]
  if (hasIntersection(taskIds as string[], runningTask.value)) {
    message.warning(t('vul.task.message.isExecuting'))
    return
  }
  const taskList = taskTableData.value.filter(task => taskIds.includes(task.task_id))
  taskList.forEach(({ task_id, cluster_id }) => {
    if (!params[cluster_id]) params[cluster_id] = { task_list: [task_id] }
    else params[cluster_id].task_list.push(task_id)
  })
  const [, res] = await api.deleteTasks(params)
  if (res) {
    const someFailed = Object.values(res).filter(value => value.label === 'Succeed')
    if (someFailed.length === Object.values(res).length) message.success(t('common.deleteSuccess'))
    else if (someFailed.length > 0) message.warning(t('common.message.partialDelete'))
    else message.error(t('common.deleteFail'))
    await queryTasks()
  }
}

const isDeleting = ref(false)

/**
 * delete tasks with task id
 * distrubition
 */
async function deleteTaskBatch() {
  if (tableState.selectedRowKeys.length === 0) {
    message.info(t('vul.task.message.atLeastOneTask'))
    return
  }
  const taskList = taskTableData.value.filter(({ task_id }) => tableState.selectedRowKeys.includes(task_id))

  Modal.confirm({
    title: t('vul.task.sentence.deleteConfirm'),
    icon: h(ExclamationCircleOutlined),
    content: `${taskList.map(({ task_name }) => task_name).join(',')}`,
    okType: 'danger',
    okText: t('common.confirm'),
    onOk: async () => {
      try {
        isDeleting.value = true
        await deleteTask(tableState.selectedRowKeys)
        tableState.selectedRowKeys = []
      } catch {
      } finally {
        isDeleting.value = false
      }
    },
  })
}
/**
 * execute task with task id
 * @param task
 */
async function handleExecuteTask(task: Task) {
  const { cluster_id, task_id } = task
  const params: DistributionParams<{ task_id: string }> = {}
  params[cluster_id] = { task_id }
  const [, res] = await api.executeTask(params)
  if (res) {
    if (res[cluster_id].label === 'Succeed') {
      message.success(t('common.succeed'))
      queryTasks()
    } else {
      message.error(res[cluster_id].label)
    }
  }
}

function handleSearch() {
  queryTasks(searchKey.value)
}

onMounted(() => {
  queryTasks()
})

onBeforeUnmount(() => {
  if (timer) {
    clearTimeout(timer)
    timer = null
  }
})
</script>

<template>
  <PageWrapper>
    <a-card>
      <a-row type="flex" justify="space-between">
        <a-col>
          <a-input-search
            v-model:value="searchKey"
            :placeholder="t('vul.task.placeHolder.searchBy')"
            :maxlength="40"
            @search="handleSearch"
          />
        </a-col>
        <a-col>
          <a-row type="flex" :gutter="6">
            <a-col v-if="tableState.selectedRowKeys.length > 0">
              <a-alert type="info" show-icon class="delete-alert">
                <template #message>
                  <span>{{ t('common.total', { count: tableState.selectedRowKeys.length }) }}</span>
                  <a @click="tableState.selectedRowKeys = []"> {{ t('common.clear') }}</a>
                </template>
              </a-alert>
            </a-col>
          </a-row>
        </a-col>
        <a-col>
          <a-button type="primary" :loading="isDeleting" @click="deleteTaskBatch">
            {{ t('common.deleteBatch') }}
          </a-button>
        </a-col>
      </a-row>
      <a-table
        row-key="task_id"
        :columns="taskTableColumns"
        :data-source="taskTableData"
        :loading="tableState.loading"
        :pagination="pagination"
        :scroll="{ x: 1260 }"
        :row-selection="{
          selectedRowKeys: tableState.selectedRowKeys,
          onChange: onSelectChange,
        }"
        @change="handleTableChange"
      >
        <template #bodyCell="{ record, column }">
          <template v-if="column.dataIndex === 'task_name'">
            <router-link
              :to="{
                path: `/vulnerability/tasks/task-detail`,
                query: { taskId: record.task_id, taskType: record.task_type },
              }"
            >
              {{ record.task_name }}
            </router-link>
          </template>
          <template v-if="column.dataIndex === 'description'">
            <a-tooltip placement="top">
              <template #title>
                <span>{{ record.description }}</span>
              </template>
              {{ cutOff(record.description) }}
            </a-tooltip>
          </template>
          <template v-if="column.dataIndex === 'status'">
            <TaskStatus :status="record.status" />
          </template>
          <template v-if="column.dataIndex === 'create_time'">
            {{ dayjs(record.create_time * 1000).format('YYYY-MM-DD HH:mm:ss') }}
          </template>
          <template v-if="column.dataIndex === 'operation'">
            <a-popconfirm @confirm="handleExecuteTask(record)">
              <template #icon>
                <PlayCircleTwoTone />
              </template>
              <template #title>
                <p>
                  {{ t('vul.task.sentence.executeTask') }}
                </p>
              </template>
              <a>{{ $t('common.execute') }}</a>
            </a-popconfirm>
            <a-divider type="vertical" />
            <a-popconfirm @confirm="deleteTask(record.task_id)">
              <template #icon>
                <QuestionCircleOutlined style="color: red" />
              </template>
              <template #title>
                <p>
                  {{ t('vul.task.sentence.deleteTask') }}
                </p>
              </template>
              <a>{{ $t('common.delete') }}</a>
            </a-popconfirm>
          </template>
        </template>
      </a-table>
    </a-card>
  </PageWrapper>
</template>
